package com.sigmatrix.h5.service.inspect;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Stream;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.sigmatrix.h5.auth.ILoginUser;
import com.sigmatrix.h5.config.TableUtils;
import com.sigmatrix.h5.entity.AdminArea;
import com.sigmatrix.h5.entity.CodeCirculation;
import com.sigmatrix.h5.entity.FirstLevelQRCode;
import com.sigmatrix.h5.entity.MultistageLevelQRCode;
import com.sigmatrix.h5.entity.v2.CodeFleeCheckRecord;
import com.sigmatrix.h5.entity.v2.DisDealer;
import com.sigmatrix.h5.entity.v2.DisTerminalShop;
import com.sigmatrix.h5.entity.v2.PackStandard;
import com.sigmatrix.h5.entity.v2.Product;
import com.sigmatrix.h5.enums.CodeCirculationStatus;
import com.sigmatrix.h5.enums.CodeInspectStatus;
import com.sigmatrix.h5.enums.CodeType;
import com.sigmatrix.h5.enums.CrmAcctType;
import com.sigmatrix.h5.enums.RegionType;
import com.sigmatrix.h5.enums.ShopType;
import com.sigmatrix.h5.exception.MessageException;
import com.sigmatrix.h5.service.AdminAreaService;
import com.sigmatrix.h5.service.CodeCirculationService;
import com.sigmatrix.h5.service.FirstLevelQrCodeService;
import com.sigmatrix.h5.service.MultistageLevelQrCodeService;
import com.sigmatrix.h5.service.db.CodeFleeCheckRecordDBService;
import com.sigmatrix.h5.service.db.DisDealerDBService;
import com.sigmatrix.h5.service.db.DisTerminalShopDBService;
import com.sigmatrix.h5.service.db.PackStandardDBservice;
import com.sigmatrix.h5.service.db.ProductDBService;
import com.sigmatrix.h5.service.db.SalesAreaDBService;
import com.sigmatrix.h5.service.inspect.CurrentQrCode.Code;
import com.sigmatrix.h5.utils.Assert;
import com.sigmatrix.h5.utils.CommonUtils;
import com.sigmatrix.h5.web.args.QueryQrCodeParamV2;
import com.sigmatrix.h5.web.mode.SigmatrixLocationWrapper;

/**
 * 基本的稽查者
 * 
 * @author wei.wang
 *
 */

public class BaseCodeInspector implements ICodeInspect {

	private static final int CODE_LEVEL_2 = 2;

	@Autowired
	private FirstLevelQrCodeService firstLevelQrCodeService;

	@Autowired
	private DisDealerDBService disDealerDBService;

	@Autowired
	private AdminAreaService adminAreaService;

	@Autowired
	private SalesAreaDBService salesAreaDBService;

	@Autowired
	private CodeFleeCheckRecordDBService codeFleeCheckRecordDBService;

	@Autowired
	private ProductDBService productDBService;

	@Autowired
	private PackStandardDBservice packStandardDBservice;

	@Autowired
	private DisTerminalShopDBService disTerminalShopDBService;

	@Autowired
	private MultistageLevelQrCodeService multistageLevelQrCodeService;

	@Autowired
	private CodeCirculationService codeCirculationService;

	@Override
	public InspectResult inspect(QueryQrCodeParamV2 vo, String esecode, ILoginUser user) {

		SigmatrixLocationWrapper currentLocation = adminAreaService.getLocation(vo.getLat(), vo.getLng());
		// 检查 location是否合法。
		if (currentLocation == null || currentLocation.getProvince() == null || currentLocation.getCity() == null) {
			throw new MessageException("经纬度地点无法解析");
		}
		// 合并
		CurrentQrCode qrCode = getQrCode(vo, esecode);

		if (qrCode == null) {
			throw new MessageException("该码不合法");
		}
		// 代理商信息。
		Agency agency = getAgency(vo, esecode);

		// 获取产品的信息。
		Product product = qrCode.getProduct();

		// 码流转信息。
		List<CodeCirculation> codeCirculations = getCirculations(product, qrCode, esecode);
		// 排序。codeCirculations
		sortCirculationOrderByTime(codeCirculations);
		// 1 码流转是否串货
		List<CodeFleeCheckRecord> codeFleeCheckRecords = fleeByCirculation(esecode, qrCode, product, codeCirculations);
		// 判断码流转 是否串货。
		boolean isflee = judge(codeFleeCheckRecords);
		// 2 稽查
		boolean isokByDealer = true;
		if (agency != null) {
			isokByDealer = inspectByDealer(agency, esecode, codeCirculations);
		}
		boolean isokByArea = false;
		if (isokByDealer) {
			// 稽查2区域
			isokByArea = inspectByArea(esecode, currentLocation, codeCirculations);
		}
		// InspectRecord
		CodeInspectionRecordResp record = buildInspectRecord(vo.getIp(), user, currentLocation, qrCode, agency,
				codeFleeCheckRecords, isokByDealer, isokByArea);

		InspectResult result = new InspectResult();
		result.setFleeCheckRecords(codeFleeCheckRecords);
		result.setInspectRecord(record);
		record.setFinalStatus((isflee && isokByDealer && isokByArea) ? 1 : 2);
		// 汇总结果返回。
		return result;
	}

	/**
	 * build CodeInspectionRecord对象。
	 * 
	 * @param ip
	 * @param user
	 * @param currentLocation
	 * @param qrCode
	 * @param agency
	 * @param codeFleeCheckRecords
	 * @param isokByDealer
	 * @param isokByArea
	 * @return
	 */
	private CodeInspectionRecordResp buildInspectRecord(String ip, ILoginUser user,
			SigmatrixLocationWrapper currentLocation, CurrentQrCode qrCode, Agency agency,
			List<CodeFleeCheckRecord> codeFleeCheckRecords, boolean isokByDealer, boolean isokByArea) {
		CodeInspectionRecordResp record = new CodeInspectionRecordResp();
		record.setQrCode(qrCode.getQrCode());
		record.setCodeType(qrCode.getCodeType());
		record.setCodeLevel(qrCode.getCurrentCode().getLevel().intValue());
		record.setSeqNum(qrCode.getCurrentSeqNum());
		record.setCreateTime(new Date());
		String recordIds = null;
		if (codeFleeCheckRecords != null && !codeFleeCheckRecords.isEmpty()) {
			final List<String> ids = new ArrayList<>();
			codeFleeCheckRecords.stream().forEach(x -> ids.add(String.valueOf(x.getId())));
			recordIds = String.join(",", ids);
		}
		record.setFleeCheckRecordIds(recordIds);
		if (agency != null) {
			record.setDealerId(agency.getDealerId());
			record.setDealerType(agency.getDealerType());
			record.setDealerName(agency.getDealerName());
		}
		record.setProductId(qrCode.getProduct().getId());
		record.setProductBatchCode(qrCode.getProductBatchCode());
		record.setProductTime(qrCode.getProductTime());
		record.setProductName(qrCode.getProduct().getName());
		if (!isokByDealer) {
			record.setStatus(CodeInspectStatus.DEALER_FLEE.value);
		} else if (!isokByArea) {
			record.setStatus(CodeInspectStatus.AREA_FLEE.value);
		} else {
			record.setStatus(CodeInspectStatus.NO_FLEE.value);
		}
		record.setIp(ip);
		record.setCreateTime(new Date());
		record.setUserId(user.getAcctId());
		record.setAccount(user.getLoginName());
		record.setPictureUrl(null);
		record.setRemark(null);
		record.setProvinceId(currentLocation.getProvince());
		record.setCityId(currentLocation.getCity());
		record.setCountyId(currentLocation.getCitySubOrdinate());
		record.setProvinceName(currentLocation.getProvinceName());
		record.setCityName(currentLocation.getCityName());
		record.setCountyName(currentLocation.getCountyName());

		if (CollectionUtils.isNotEmpty(qrCode.getPackStandards()) && record.getCodeLevel() != null) {
			for (PackStandard ps : qrCode.getPackStandards()) {
				if (ps.getLevel().intValue() == record.getCodeLevel().intValue()) {
					record.setCodeLevelName(ps.getName());
					break;
				}
			}
		}

		return record;
	}

	/**
	 * 得到代理商的信息。
	 * 
	 * @param vo
	 * @param esecode
	 * @return
	 */
	private Agency getAgency(QueryQrCodeParamV2 vo, String esecode) {
		if (vo.getDealerId() == null || vo.getDealerType() == null) {
			return null;
		}
		Agency agency = new Agency();
		agency.setDealerId(vo.getDealerId());
		agency.setDealerType(vo.getDealerType());
		if (vo.getDealerType() == CrmAcctType.DEALER.value.intValue()) {
			DisDealer dealer = disDealerDBService.selectById(vo.getDealerId(), TableUtils.tablePrefixBy(esecode));
			if (dealer == null) {
				throw new MessageException("该经销商不存在");
			}
			agency.setDealerName(dealer.getName());
			agency.setDealer(dealer);
		} else if (vo.getDealerType() == CrmAcctType.TERMINAL_SHOP.value.intValue()) {
			DisTerminalShop shop = disTerminalShopDBService.selectById(vo.getDealerId(),
					TableUtils.tablePrefixBy(esecode));
			if (shop == null) {
				throw new MessageException("该门店不存在");
			}
			agency.setDealerName(shop.getName());
		} else {
			throw new MessageException("暂时不支持此类型");
		}
		return agency;
	}

	/**
	 * 码流转 串货判断。
	 * 
	 * @param codeFleeCheckRecords
	 * @return false 串货，true 没串货。
	 */
	private boolean judge(List<CodeFleeCheckRecord> codeFleeCheckRecords) {

		if (codeFleeCheckRecords == null) {
			return true;
		}
		return codeFleeCheckRecords.stream().anyMatch(x -> {
			if (CodeInspectStatus.isFlee(x.getStatus())) {
				return false;
			} else {
				return true;
			}
		});
	}

	@Override
	public boolean inspectByDealer(Agency agency, String esecode, List<CodeCirculation> codeCirculations) {

		if (codeCirculations == null || codeCirculations.isEmpty()) {
			return true;
		}

		if (agency.getDealerType() == CrmAcctType.DEALER.value.intValue()) {
			// 稽查点为经销商
			boolean isflee = inspectOnDealer(codeCirculations, agency.getDealer(), esecode);
			return isflee;
		} else if (agency.getDealerType() == CrmAcctType.TERMINAL_SHOP.value.intValue()) {
			// 稽查点为门店
			DisTerminalShop shop = disTerminalShopDBService.selectById(agency.getDealerId(),
					TableUtils.tablePrefixBy(esecode));
			boolean isflee = inspectOnShop(codeCirculations.get(codeCirculations.size() - 1), shop, esecode);
			return isflee;
		} else {
			// 其他不支持
			throw new MessageException("不支持此类型的经销商。");
		}
	}

	@Override
	public List<CodeFleeCheckRecord> fleeByCirculation(String esecode, CurrentQrCode qrCode, Product product,
			List<CodeCirculation> codeCirculations) {
		if (codeCirculations == null || codeCirculations.isEmpty()) {
			// 没有串货
			return null;
		}
		List<CodeFleeCheckRecord> codeFleeCheckRecords = flee(product, qrCode, codeCirculations, esecode);
		return codeFleeCheckRecords;
	}

	@Override
	public boolean inspectByArea(String esecode, SigmatrixLocationWrapper currentLocation,
			List<CodeCirculation> codeCirculations) {
		if (codeCirculations == null || codeCirculations.isEmpty()) {
			return true;
		}
		boolean isareaOk = false;
		CodeCirculation circulationLast = codeCirculations.get(codeCirculations.size() - 1);
		// 门店
		if (circulationLast.getDealersType() == CrmAcctType.TERMINAL_SHOP.value.intValue()) {
			DisTerminalShop shop = disTerminalShopDBService.selectByCode(esecode, circulationLast.getDealersCode());
			if (currentLocation.getCitySubOrdinate() != null
					&& currentLocation.getCitySubOrdinate().equals(shop.getCitySubOrdinate())) {
				isareaOk = true;
			} else if (currentLocation.getCitySubOrdinate() == null && shop.getCitySubOrdinate() == null) {
				if (currentLocation.getCity() != null && currentLocation.getCity().equals(shop.getCity())) {
					isareaOk = true;
				} else {
					isareaOk = false;
				}
			} else {
				isareaOk = false;
			}

			// 经销商
		} else if (circulationLast.getDealersType() == CrmAcctType.DEALER.value.intValue()) {
			DisDealer dealer = disDealerDBService.selectByCode(esecode, circulationLast.getDealersCode());
			if (dealer == null) {
				throw new MessageException("数据异常。dealer:" + circulationLast.getDealersCode());
			}
			isareaOk = inspectArea(currentLocation, dealer, esecode);
		} else {
			throw new MessageException("非法数据");

		}
		return isareaOk;
	}

	@Override
	public List<CodeFleeCheckRecord> fleeByCirculation(String esecode, CurrentQrCode qrCode, Product product) {
		List<CodeCirculation> codeCirculations = getCirculations(product, qrCode, esecode,
				CodeCirculationStatus.SALES_OUT_STORAGE);
		if (codeCirculations == null || codeCirculations.isEmpty()) {
			// 没有串货
			return null;
		}
		List<CodeFleeCheckRecord> codeFleeCheckRecords = flee(product, qrCode, codeCirculations, esecode);
		return codeFleeCheckRecords;
	}

	@Override
	public List<CodeFleeCheckRecord> fleeByCirculation(String esecode, CurrentQrCode qrCode, Product product,
			CodeCirculationStatus status) {
		List<CodeCirculation> codeCirculations = getCirculations(product, qrCode, esecode, status);
		if (codeCirculations == null || codeCirculations.isEmpty()) {
			// 没有串货
			return null;
		}
		List<CodeFleeCheckRecord> codeFleeCheckRecords = flee(product, qrCode, codeCirculations, esecode);
		return codeFleeCheckRecords;
	}

	@Override
	public CurrentQrCode getQrCode(QueryQrCodeParamV2 param, String esecode) {
		if (param == null || StringUtils.isEmpty(param.getQrCode()) || param.getCodeType() == null) {
			throw new MessageException("非法入参");
		}
		CurrentQrCode currentQrCode = new CurrentQrCode();
		currentQrCode.setQrCode(param.getQrCode());
		currentQrCode.setCodeType(param.getCodeType());
		{
			FirstLevelQRCode firstCode = null;
			if (CodeType.SEQ_NUM.value.equals(param.getCodeType())) {
				// seqNum
				firstCode = firstLevelQrCodeService.findBySeqNum(currentQrCode.getQrCode(), esecode);
			} else {
				// qrcode
				firstCode = firstLevelQrCodeService.findByQRCode(CommonUtils.encodeQRCode(currentQrCode.getQrCode()),
						esecode);
			}

			// 如果不存在，查询多级码表
			if (firstCode == null) {
				MultistageLevelQRCode multistageLevelQRCode = null;
				if (CodeType.SEQ_NUM.value.equals(param.getCodeType())) {
					// seqNum
					multistageLevelQRCode = multistageLevelQrCodeService.findBySeqNum(currentQrCode.getQrCode(),
							esecode);
				} else {
					// qrcode
					multistageLevelQRCode = multistageLevelQrCodeService
							.findByPackContent(CommonUtils.encodeQRCode(currentQrCode.getQrCode()), esecode);
				}
				if (multistageLevelQRCode == null) {
					throw new MessageException("该二维码没有查询到信息。");
				}
				currentQrCode.setCurrentCode(currentQrCode.buildCode(multistageLevelQRCode.getPackContent(),
						multistageLevelQRCode.getPackLevel().shortValue()));
				currentQrCode.setCurrentSeqNum(multistageLevelQRCode.getSeqNum());
				currentQrCode.setProductTime(multistageLevelQRCode.getProductTime());
				currentQrCode.setProductBatchCode(multistageLevelQRCode.getBatchCode());
				currentQrCode.getCurrentCode().setParentQrcode(multistageLevelQRCode.getParentCode());
				if (StringUtils.isNotEmpty(multistageLevelQRCode.getChilds())) {
					String[] split = multistageLevelQRCode.getChilds().split(",");
					if (split.length > 0) {
						currentQrCode.getCurrentCode().setChildQrcode(split[0]);
					}
				}
				// 获取产品信息。
				Product product = productDBService.selectById(multistageLevelQRCode.getProductId(),
						TableUtils.tablePrefixBy(esecode));
				if (product == null) {
					throw new MessageException("该产品不存在。");
				}
				currentQrCode.setProduct(product);
			} else {
				currentQrCode.setCurrentCode(currentQrCode.buildCode(firstCode.getQrCode(), (short) 1));
				currentQrCode.getCurrentCode().setParentQrcode(firstCode.getParentCode());
				currentQrCode.setCurrentSeqNum(firstCode.getSeqNum());
				currentQrCode.setProductTime(firstCode.getProductTime());
				currentQrCode.setProductBatchCode(firstCode.getBatchCode());
				// 获取产品信息。
				Product product = productDBService.selectById(firstCode.getProductId(),
						TableUtils.tablePrefixBy(esecode));
				if (product == null) {
					throw new MessageException("该产品不存在。");
				}
				currentQrCode.setProduct(product);
			}
		}

		// 包装规格信息
		PackStandard ps = new PackStandard();
		ps.setTablePrefix(TableUtils.tablePrefixBy(esecode));
		ps.setProductId(currentQrCode.getProduct().getId());
		List<PackStandard> packStandards = packStandardDBservice.selectList(new EntityWrapper<PackStandard>(ps));
		currentQrCode.setPackStandards(packStandards);

		Short currentLevel = currentQrCode.getCurrentCode().getLevel();
		if (currentLevel > currentQrCode.getProduct().getPackLevel()) {
			throw new MessageException("不支持该级别的码");
		}

		if (currentLevel == currentQrCode.getProduct().getPackLevel()) {
			return currentQrCode;
		}

		// 当介于一级码和包装码之间，如果存在包装码-》填充包装码
		{
			String cursor = currentQrCode.getCurrentCode().getParentQrcode();
			while (true) {
				if (StringUtils.isEmpty(cursor)) {
					break;
				}
				MultistageLevelQRCode parentLevel2 = multistageLevelQrCodeService.findByPackContent(cursor, esecode);
				if (parentLevel2 == null) {
					break;
				}
				if (parentLevel2.getPackLevel().intValue() == currentQrCode.getProduct().getPackLevel().intValue()) {
					List<Code> parentCodes = currentQrCode.getParentCode();
					parentCodes.add(currentQrCode.buildCode(parentLevel2.getPackContent(),
							parentLevel2.getPackLevel().shortValue()));
					break;
				}

				cursor = parentLevel2.getParentCode();
			}
		}

		// 当介于一级码和包装码之间，如果存在一级码-》填充一级码
		{
			if (currentQrCode.getCurrentCode().getLevel() == CODE_LEVEL_2) {
				List<Code> childCodes = currentQrCode.getChildCode();
				childCodes.add(currentQrCode.buildCode(currentQrCode.getCurrentCode().getChildQrcode(), (short) 1));
			}
			if (currentLevel > CODE_LEVEL_2) {
				String firstLevelCode = null;
				String cursor = null;
				cursor = currentQrCode.getCurrentCode().getChildQrcode();
				while (true) {
					if (StringUtils.isEmpty(cursor)) {
						break;
					}
					MultistageLevelQRCode parentLevel2 = multistageLevelQrCodeService.findByPackContent(cursor,
							esecode);
					if (parentLevel2 == null) {
						break;
					}
					String children = parentLevel2.getChilds();
					if (StringUtils.isNotEmpty(children)) {
						String[] split = children.split(",");
						if (split.length > 0) {
							cursor = split[0];
						} else {
							break;
						}
					} else {
						break;
					}
					if (parentLevel2.getPackLevel().intValue() == 2) {
						firstLevelCode = cursor;
						break;
					}
				}
				if (StringUtils.isEmpty(firstLevelCode)) {
					List<Code> childCodes = currentQrCode.getChildCode();
					childCodes.add(currentQrCode.buildCode(firstLevelCode, (short) 1));
				}
			}
		}
		return currentQrCode;
	}

	/**
	 * 稽查区域
	 * 
	 * @param location
	 * @param dealer
	 * @return
	 */
	boolean inspectArea(SigmatrixLocationWrapper location, DisDealer dealer, String esecode) {
		if (dealer == null || location == null) {
			throw new MessageException("非法入参");
		}
		Stream<AdminArea> adminAreaStream = saleArea2AdminArea(dealer, esecode);
		if (adminAreaStream == null) {
			return false;
		}
		boolean isCatch = adminAreaStream.anyMatch(x -> x.getId().equals(location.getCity())
				|| x.getId().equals(location.getCitySubOrdinate()) || x.getId().equals(location.getProvince()));
		return isCatch;
	}

	protected List<CodeCirculation> getCirculations(Product product, CurrentQrCode code, String eseCode,
			CodeCirculationStatus status) {
		if (status != CodeCirculationStatus.IN_STORAGE && status != CodeCirculationStatus.SALES_OUT_STORAGE) {
			throw new MessageException("不支持该流转类型");
		}
		// 如果是箱码（包装级别）。--箱码的流转记录
		if (code.getCurrentCode().getLevel().equals(product.getPackLevel())) {
			List<CodeCirculation> circulations = codeCirculationService
					.findListByQrCode(code.getCurrentCode().getQrcode(), eseCode, status);
			return circulations;
		}

		// 如果是盒码()。 --瓶码的流转记录
		// --箱码的流转记录
		Short packLevel = product.getPackLevel();
		Short currentLevel = code.getCurrentCode().getLevel();
		if (packLevel > currentLevel.shortValue() && currentLevel.shortValue() < 1) {
			List<CodeCirculation> circulations = new ArrayList<>();
			if (!code.getChildCode().isEmpty()) {
				List<CodeCirculation> circulation1 = null;
				circulation1 = codeCirculationService.findListByQrCode(code.getChildCode().get(0).getQrcode(), eseCode,
						status);
				if(circulation1 != null){					
					circulations.addAll(circulation1);
				}
			}
			// 第一条为企业发货不继续查。
			if (circulations != null && !circulations.isEmpty()) {
				sortCirculationOrderByTime(circulations);
				CodeCirculation codeCirculation = circulations.get(0);
				if (codeCirculation.getOrganizationType().equals(1)) {
					return circulations;
				}
			}

			// 否则继续查箱码
			if (!code.getParentCode().isEmpty()) {
				List<CodeCirculation> circulations2 = null;
				circulations2 = codeCirculationService.findListByQrCode(code.getParentCode().get(0).getQrcode(),
						eseCode, status);
				if(circulations2 !=null){					
					circulations.addAll(circulations2);
				}
			}
			return circulations;
		}

		// 如果是瓶码。--瓶码的流转记录
		// --箱码的流转记录
		if (currentLevel.shortValue() == 1) {

			List<CodeCirculation> circulations = new ArrayList<>();
			List<CodeCirculation> circulation1 = codeCirculationService
					.findListByQrCode(code.getCurrentCode().getQrcode(), eseCode, status);
			if(circulation1!=null){				
				circulations.addAll(circulation1);
			}
			// 第一条为企业发货不继续查。
			if (circulations != null && !circulations.isEmpty()) {
				sortCirculationOrderByTime(circulations);
				CodeCirculation codeCirculation = circulations.get(0);
				if (codeCirculation.getOrganizationType().equals(1)) {
					return circulations;
				}
			}

			// 否则继续查箱码
			if (!code.getParentCode().isEmpty()) {
				List<CodeCirculation> circulations2 = null;
				circulations2 = codeCirculationService.findListByQrCode(code.getParentCode().get(0).getQrcode(),
						eseCode, status);
				if(circulations2 != null){
					circulations.addAll(circulations2);
					
				}
			}
			return circulations;

		}
		// 其他级别不存在。
		return null;
	}

	/**
	 * 
	 * 
	 * 获取码流转: 判断码类型。 如果是瓶码:--瓶码的流转记录 --箱码的流转记录 如果是盒码:--瓶码的流转记录 --箱码的流转记录
	 * 如果是箱码:--箱码的流转记录 其他：一直向上找包装单位停止 （盒-->瓶 瓶-->箱-->向上找包装单位）
	 * 
	 * @param product
	 * @param code
	 * @return
	 */
	protected List<CodeCirculation> getCirculations(Product product, CurrentQrCode code, String eseCode) {
		return getCirculations(product, code, eseCode, CodeCirculationStatus.SALES_OUT_STORAGE);
	}

	/**
	 * 串货检查：（以时间轴排序）当前流转记录 和 前一个流转记录进行判断。
	 * 
	 * @param product
	 * @param code
	 * @param circulationPre
	 *            前一个流转记录
	 * @param circulationCurrent
	 *            当前流转记录
	 * @param esecode
	 * @return
	 */
	boolean flee(Product product, CurrentQrCode code, CodeCirculation circulationPre,
			CodeCirculation circulationCurrent, String esecode) {
		if (circulationPre == null || circulationCurrent == null) {
			throw new MessageException("入参错误");
			// 没有 ------------------》没有串货
			// 有 ：判断是否包含关系
			// 否 ------------------》串货
			// 是 ------------------》没串货
		}
		if (circulationCurrent.getOrganizationCode().equals(circulationPre.getDealersCode())) {
			return true;
		} else {
			List<DisDealer> dealerParents = disDealerDBService
					.findParentsByCode(circulationCurrent.getOrganizationCode(), esecode);
			if (dealerParents == null) {
				return false;
			}
			boolean isMatch = dealerParents.stream().anyMatch(x -> x.getCode().equals(circulationPre.getDealersCode()));
			if (isMatch) {
				return true;
			} else {
				return false;
			}
		}
	}

	/**
	 * 串货检查
	 * 
	 * @param product
	 * @param code
	 * @param circulations
	 * @param esecode
	 * @return
	 */
	List<CodeFleeCheckRecord> flee(Product product, CurrentQrCode code, List<CodeCirculation> circulations,
			String esecode) {
		// 码流转集合-根据时间排序。
		sortCirculationOrderByTime(circulations);
		List<CodeFleeCheckRecord> records = new ArrayList<>();
		// 第一条
		records.add(saveFlee(esecode, code, product, circulations.get(0), true));
		//
		for (int i = 1; i < circulations.size(); i++) {
			boolean isok = flee(product, code, circulations.get(i - 1), circulations.get(i), esecode);
			records.add(saveFlee(esecode, code, product, circulations.get(i), isok));
		}
		return records;
	}

	/**
	 * 保存记录。
	 * 
	 * @param code
	 * @param product
	 * @param circulationCurrent
	 * @param isflee
	 * @return
	 */
	private CodeFleeCheckRecord saveFlee(String esecode, CurrentQrCode code, Product product,
			CodeCirculation circulationCurrent, boolean isok) {
		// 查询。
		CodeFleeCheckRecord recordQ = codeFleeCheckRecordDBService.findByCirIdAndQrcode(circulationCurrent.getId(),
				circulationCurrent.getQrCode(), esecode);
		if (recordQ != null) {
			return recordQ;
		}
		// 插入
		CodeFleeCheckRecord record = new CodeFleeCheckRecord();
		record.setTablePrefix(TableUtils.tablePrefixBy(esecode));
		record.setQrCode(circulationCurrent.getQrCode());
		record.setCodeLevel(circulationCurrent.getLevel());
		record.setCirculationId(circulationCurrent.getId());
		record.setCirculationType(circulationCurrent.getStatus());
		record.setCheckTime(circulationCurrent.getCreateTime());
		record.setProductId(product.getId());
		record.setProductBatchCode(circulationCurrent.getProductBatchCode());
		if (CollectionUtils.isNotEmpty(code.getPackStandards()) && record.getCodeLevel() != null) {
			for (PackStandard ps : code.getPackStandards()) {
				if (ps.getLevel().intValue() == record.getCodeLevel().intValue()) {
					record.setCodeLevelName(ps.getName());
					break;
				}
			}
		}
		record.setProductTime(code.getProductTime());
		if (isok) {
			record.setStatus(CodeInspectStatus.NO_FLEE.value);
		} else {
			record.setStatus(CodeInspectStatus.DEALER_FLEE.value);
		}
		record.setSenderCode(circulationCurrent.getOrganizationCode());
		record.setSenderName(circulationCurrent.getOrganizationName());
		record.setSenderType(circulationCurrent.getOrganizationType());
		record.setReceiverCode(circulationCurrent.getDealersCode());
		record.setReceiverName(circulationCurrent.getDealersName());
		record.setReceiverType(circulationCurrent.getDealersType());
		codeFleeCheckRecordDBService.insert(record);
		return record;
	}

	/**
	 * 稽查 稽查点为经销商。 （即在经销商处稽查）
	 * 
	 * @param circulationLast
	 * @param dealer
	 * @return
	 */
	boolean inspectOnDealer(List<CodeCirculation> circulations, DisDealer dealer, String esecode) {

		// 当稽查指定地点为经销商，同时稽查指定地点在有可能在流转链中间，或在流转链外。

		if (dealer.getCode().equals(circulations.get(circulations.size() - 1).getDealersCode())) {
			return true;
		}
		{
			// 最后一条码流转记录接收方 在稽查的经销商的父经销商树中--ok
			List<DisDealer> checkPiontParents = disDealerDBService.findParentsById(dealer.getId(), esecode);
			if (checkPiontParents != null && !checkPiontParents.isEmpty()) {
				boolean isok = checkPiontParents.stream()
						.anyMatch(x -> x.getCode().equals(circulations.get(circulations.size() - 1).getDealersCode()));
				if (isok) {
					return isok;
				}
			}
		}

		{
			// 在流转在流转链中----ok
			boolean isok = circulations.stream().anyMatch(x -> x.getDealersCode().equals(dealer.getCode()));
			// 其他 ----ng
			if (isok) {
				return isok;
			}
		}
		{
			CodeCirculation lastRecord = circulations.get(circulations.size() - 1);
			String dealerCode = null;
			if (lastRecord.getDealersType().intValue() == CrmAcctType.TERMINAL_SHOP.value.intValue()
					&& lastRecord.getOrganizationType().intValue() == CrmAcctType.ENTERPRISE.value.intValue()) {

				throw new MessageException("数据异常。(企业不可以直接出库给门店)");
				// DisTerminalShop shop =
				// disTerminalShopDBService.selectByCode(esecode,
				// lastRecord.getDealersCode());
				// if(shop == null){
				// throw new
				// MessageException("数据异常。code："+lastRecord.getDealersCode());
				// }
				// dealerCode = lastRecord.getOrganizationCode();//
				// DisTerminalShopDetail detail = new DisTerminalShopDetail();
				// detail.setTablePrefix(TableUtils.tablePrefixBy(esecode));
				// detail.setTerminalShopId(shop.getId());
				// List<DisTerminalShopDetail> details =
				// disTerminalShopDetailDBService.selectList(new
				// EntityWrapper<DisTerminalShopDetail>(detail));
				// if(details==null||details.isEmpty()){
				// throw new
				// MessageException("数据异常。code："+lastRecord.getDealersCode());
				// }
				// details.get(0).getDealerId()//得到经销商

			} else if (lastRecord.getDealersType() == CrmAcctType.TERMINAL_SHOP.value.intValue()) {
				dealerCode = lastRecord.getOrganizationCode();
			} else {
				dealerCode = lastRecord.getDealersCode();
			}
			// 稽查的经销商 在最后一条码流转记录接收方的父经销商树中--ok
			List<DisDealer> lastRecordParents = disDealerDBService.findParentsByCode(dealerCode, esecode);
			if (lastRecordParents != null && !lastRecordParents.isEmpty()) {
				boolean isok = lastRecordParents.stream().anyMatch(x -> x.getCode().equals(dealer.getCode()));
				if (isok) {
					return isok;
				}
			}
			return false;
		}
	}

	/**
	 * 2 稽查 稽查点为门店。（即在门店处稽查）
	 * 
	 * @param circulationLast
	 * @param shop
	 * @return
	 */
	boolean inspectOnShop(CodeCirculation circulationLast, DisTerminalShop shop, String esecode) {

		// 最后一个不为门店----ok
		if (circulationLast.getDealersType() == CrmAcctType.DEALER.value.intValue()) {
			return true;
		}

		//  最后一个门店且相等----ok
		if (circulationLast.getDealersType() == CrmAcctType.TERMINAL_SHOP.value.intValue()
				&& shop.getCode().equals(circulationLast.getDealersCode())) {
			return true;
		}

		// 最后一个门店且为虚拟门店----ok
		if (circulationLast.getDealersType() == CrmAcctType.TERMINAL_SHOP.value.intValue()) {
			DisTerminalShop circShop = disTerminalShopDBService.selectByCode(esecode, circulationLast.getDealersCode());
			if (circShop.getType().shortValue() == ShopType.VIRTUAL_STORE.value.shortValue()) {
				return true;
			}

		}
		// 其他----Ng
		return false;
	}

	/**
	 * 获取经销商所有的行政区域
	 * 
	 * @param dealer
	 * @return
	 */
	private Stream<AdminArea> saleArea2AdminArea(DisDealer dealer, final String esecode) {
		Assert.notNull(dealer.getSalesRegion(), "销售区域为空");
		String[] regions = dealer.getSalesRegion().split(",");
		Stream<AdminArea> f = null;
		// 如果类型为销售区域，将销售区域转化为行政区域
		if (RegionType.SALES_AREA.value.equals(dealer.getRegionType())) {
			f = Arrays.stream(regions)
					.map(x -> StringUtils.isBlank(x) ? null
							: salesAreaDBService.selectById(Integer.valueOf(x), TableUtils.tablePrefixBy(esecode)))
					// 获取所有销售区域对应的行政区域ID
					.flatMap(s -> (s == null || StringUtils.isBlank(s.getZoneCodes())) ? null
							: Arrays.stream(s.getZoneCodes().split(",")))
					// 根据行政区域ID查询行政区域
					.map(x -> {
						if (StringUtils.isBlank(x)) {
							return null;
						}
						AdminArea area = adminAreaService.findByIdFromCache(Integer.valueOf(x));
						return area;
					});
		} else {
			f = Arrays.stream(regions).map(x -> {
				if (StringUtils.isBlank(x)) {
					return null;
				}
				AdminArea area = adminAreaService.findByIdFromCache(Integer.valueOf(x));
				return area;
			});
		}
		return f;
	}

	/**
	 * 
	 * 根据时间正向排序。 即get(0)为时间最小的，索引越大时间值越大。
	 * 
	 * @param circulations
	 */
	private void sortCirculationOrderByTime(List<CodeCirculation> circulations) {
		if (circulations == null || circulations.isEmpty()) {
			return;
		}
		circulations.sort((x, y) -> x.getCreateTime().before(y.getCreateTime()) ? -1 : 1);
	}

	public static void main(String[] args) {

		List<CodeCirculation> circulations = new ArrayList<>();
		{
			CodeCirculation cir = new CodeCirculation();
			cir.setId("1ji");
			cir.setStatus(1);
			cir.setCreateTime(new Date());
			circulations.add(cir);
		}
		{
			CodeCirculation cir = new CodeCirculation();
			cir.setId("2xiao");
			cir.setStatus(2);
			cir.setCreateTime(new Date(System.currentTimeMillis() - 10000));
			circulations.add(cir);
		}
		{
			CodeCirculation cir = new CodeCirculation();
			cir.setId("3da");
			cir.setStatus(3);
			cir.setCreateTime(new Date(System.currentTimeMillis() + 10000));
			circulations.add(cir);
		}
		{
			CodeCirculation cir = new CodeCirculation();
			cir.setId("4xiaoxiao");
			cir.setStatus(4);
			cir.setCreateTime(new Date(System.currentTimeMillis() - 20000));
			circulations.add(cir);
		}
		{
			CodeCirculation cir = new CodeCirculation();
			cir.setId("5dada");
			cir.setStatus(5);
			cir.setCreateTime(new Date(System.currentTimeMillis() + 20000));
			circulations.add(cir);
		}

		if (circulations == null || circulations.isEmpty()) {
			return;
		}

		final List<String> ids = new ArrayList<>();
		circulations.stream().forEach(x -> ids.add(x.getId()));
		String joinBydaohao = String.join(",", ids);
		// (x -> {
		// return String.valueOf(x.getId());
		// }).toArray());
		System.out.println(joinBydaohao);
	}

}
